#include "play.h"

play::play()
{}

play::play(const sound& s)
{
    set_sound(s);
}

BOOL play::writeOutAudioBlock(LPSTR block, DWORD size)
{
    wHdr.dwBufferLength = size;
    wHdr.lpData = block;
    if (MMSYSERR_NOERROR != waveOutPrepareHeader(phwo, &wHdr, sizeof(WAVEHDR)))
    {
        // fprintf(stderr, "文件缓冲区准备失败！\n");
        return FALSE;
    }

//    waveOutWrite(phwo, &wHdr, sizeof(WAVEHDR));
    if (MMSYSERR_NOERROR != waveOutWrite(phwo, &wHdr, sizeof(WAVEHDR)))
    {
        // fprintf(stderr, "写文件缓冲区失败！\n");
        return FALSE;
    }
    Sleep(500);

    return TRUE;
}

BOOL play::closeOutAudioBlock()
{
    return (MMSYSERR_NOERROR == waveOutClose(phwo));
}

void play::set_sound(const sound& s)
{
//    closeOutAudioBlock();
    UINT count = waveOutGetNumDevs();
    if (count == 0)
        throw play_exception("There are no devices to play audio.");
    //    WAVEOUTCAPS waveOutcaps;
    //    MMRESULT mmResult = waveOutGetDevCaps(0, std::addressof(waveOutcaps), sizeof(WAVEINCAPS)); // 2设备描述
    //    if (mmResult not_eq MMSYSERR_NOERROR)
    //        throw play_exception("Exception when calling waveOutGetDevCaps with mmResult " + std::to_string(mmResult) + '.');


    pwfx = {
        .wFormatTag = WAVE_FORMAT_PCM,
        .nChannels = s.channel,
        .nSamplesPerSec = s.frequency,
        .nAvgBytesPerSec = s.bytes_per_second,
        .nBlockAlign = s.channel * s.bits >> 3,
        .wBitsPerSample = s.bits,
        .cbSize = 0	// WAVE_FORMAT_PCM格式下忽略此量，非PCM可用来存储wFormatTag的额外属性
    };

    if (MMSYSERR_NOERROR != waveOutOpen(nullptr, 0, std::addressof(pwfx), 0, 0, WAVE_FORMAT_QUERY))
        throw play_exception("This format has not been supported by the audio ouput device.");
    if (MMSYSERR_NOERROR != waveOutOpen(std::addressof(phwo), WAVE_MAPPER, std::addressof(pwfx), 0, 0, CALLBACK_NULL))
        throw play_exception("Failed to open file. (waveOutOpen)");
}

void play::pause()
{
    waveOutPause(phwo);
}

void play::reset()
{
    waveOutReset(phwo);
}

void play::restart()
{
    waveOutRestart(phwo);
}

void play::unprepare()
{
    while (WAVERR_STILLPLAYING == waveOutUnprepareHeader(phwo, &wHdr, sizeof(WAVEHDR)))
    {
        Sleep(100);
    }
}
